import tarfile
import traceback
import sys
import os
import glob
import gmalg
import base64
import binascii
import datetime as dt

from loguru import logger
from pyqttoast import Toast, ToastPreset
from PySide6.QtWidgets import QApplication, QDialog, QStyleFactory, QFileDialog, \
    QMessageBox
from PySide6.QtCore import QThreadPool, QSettings, Qt, QRunnable, Slot, \
    QObject, Signal
from .form import Ui_Form



class WorkerSignals(QObject):
    finished = Signal()
    error = Signal(tuple)
    result = Signal(object)
    progress = Signal(int)
    

class GMSSLPackUploadWorker(QRunnable):
    def __init__(self, fn, *args, **kwargs):
        super(GMSSLPackUploadWorker, self).__init__()
        # Store constructor arguments (re-used for processing)
        self.fn = fn
        self.args = args
        self.kwargs = kwargs
        self.signals = WorkerSignals()

        # Add the callback to our kwargs
        self.kwargs['progress_callback'] = self.signals.progress

    @Slot()
    def run(self):
        try:
            result = self.fn(*self.args, **self.kwargs)
        except:
            traceback.print_exc()
            exctype, value = sys.exc_info()[:2]
            self.signals.error.emit((exctype, value, traceback.format_exc()))
        else:
            self.signals.result.emit(result)  # Return the result of the processing
        finally:
            self.signals.finished.emit()  # Done


class GMSSLUPloadMainWindow(QDialog, Ui_Form):
    
    def __init__(self, parent=None):
        super(GMSSLUPloadMainWindow, self).__init__(parent)
        self.setupUi(self)
        self.setWindowTitle('电站离线数据打包上传')
        self.threadpool = QThreadPool()
        self.settings = QSettings('config.ini', QSettings.IniFormat)
        self.reload_settings()
        self.pushButtonPackUpload.clicked.connect(self.package_files)
        self.pushButtonTargetPath.clicked.connect(self.open_file_dialg)

    def update_mpoint(self):
        self.settings.setValue('default/mpoint', self.lineEditMPoint.text())
    
    def update_publickey(self):
        self.settings.setValue('default/publickey', self.lineEditPublicKey.text())

    def update_code(self):
        self.settings.setValue('default/code', self.lineEditCode.text())

    @property
    def mpoint(self) -> str:
        return self.lineEditMPoint.text()
    
    @property
    def code(self) -> str:
        return self.lineEditCode.text()
    
    @property
    def publickey(self) -> str:
        return self.lineEditPublicKey.text()

    @property
    def valid_publickey(self) -> bytes:
        key = base64.b64decode(self.publickey)
        return binascii.hexlify(key)[52:]

    
    @property
    def uploadpath(self) -> str:
        return self.settings.value('default/uploadpath', '')

    def reload_settings(self):
        # self.lineEditUsername.setText(self.settings.value('default/username', ''))
        self.lineEditCode.setText(self.settings.value('default/code', ''))
        self.lineEditPublicKey.setText(self.settings.value('default/publickey', ''))
        self.lineEditTargetPath.setText(self.settings.value('default/uploadpath', ''))
        self.lineEditMPoint.setText(self.settings.value('default/mpoint', ''))

    def open_file_dialg(self):
        dir_path = QFileDialog.getExistingDirectory(self, "打开文件夹", "/home",
                                                QFileDialog.ShowDirsOnly
                                                | QFileDialog.DontResolveSymlinks)
        if dir_path:
            self.settings.setValue('default/uploadpath', dir_path)
            self.lineEditTargetPath.setText(dir_path)

    def package_files(self):
        logger.info(f"==> {self.uploadpath} {self.code} {self.publickey}")
        if not self.uploadpath:
            # self.show_toast("打包源文件夹未设置")
            msgBox = QMessageBox()
            msgBox.setText("打包源文件夹路径未设置")
            msgBox.exec()
            return
        if not os.path.exists(self.uploadpath):
            msgBox = QMessageBox()
            msgBox.setText("打包源文件夹路径未设置")
            msgBox.exec()
            # self.show_toast("打包源文件夹未设置")
            return
        if not self.publickey:
            msgBox = QMessageBox()
            msgBox.setText("电站公钥未设置")
            msgBox.exec()
            # self.show_toast("公钥未设置")
            return
        if not self.code:
            msgBox = QMessageBox()
            msgBox.setText("电站编号未设置")
            msgBox.exec()
            return
        if self.mpoint is None:
            msgBox = QMessageBox()
            msgBox.setText("电站监测点未设置")
            msgBox.exec()
            # self.show_toast("电站监测点未设置")
            return
        self.update_code()
        self.update_mpoint()
        self.update_publickey()
        target_dir = os.path.join(os.path.abspath(os.path.curdir), 'packages')
        if not os.path.exists(target_dir):
            os.mkdir(target_dir)
        dstr = dt.datetime.now().strftime('%Y%m%d%H.tar')
        filename = f'{self.code}-{self.mpoint}-{dstr}'
        tar_file_path = os.path.join(target_dir, filename)
        tarf = tarfile.open(tar_file_path, 'w')
        for filepath in glob.glob(os.path.join(self.uploadpath, '*')):
            if not os.path.isfile(filepath):
                continue
            tarf.add(filepath, arcname=os.path.split(filepath)[1])
        tarf.close()
        with open(tar_file_path, 'rb') as fd:
            data = fd.read()
        with open(tar_file_path, 'wb') as fd:
            sm2_enc = gmalg.SM2(pk=binascii.unhexlify(self.valid_publickey))
            edata = sm2_enc.encrypt(data)
            fd.write(edata)
        # self.show_toast("压缩打包加密成功！")
        msgBox = QMessageBox()
        msgBox.setText("压缩打包加密成功")
        msgBox.exec()

    def show_toast(self, message: str, level=ToastPreset.SUCCESS):
        toast = Toast(self)
        toast.setDuration(3000)  # Hide after 5 seconds
        toast.setTitle('消息信息')
        toast.setText(message)
        toast.applyPreset(level)  # Apply style preset
        toast.show()